<template>
  <div ref="canvasContainer" class="canvas-container" v-loading="loading">
    <div :class="['catalogue', hide ? 'catalogue-hide' : '']">
      <canvas
        v-for="(page, indexnum) in pages"
        :key="page"
        :id="'catalogue' + page"
        :class="[indexnum === index - 1 ? 'checked' : '']"
        @click="jumpTo(indexnum + 1)"
      ></canvas>
    </div>
    <div :class="['main', hide ? '' : 'main-narrow']">
      <!-- <div class="header">
        <div class="control">
          <div class="control-button" @click="showCatalogue">
            <img
              src=""
              alt=""
            />
          </div>
          <div class="control-button" @click="autoPagerChrome">
            <img
              src=""
              alt=""
            />
          </div>
          <div class="control-button" @click="jumpTo(1)">
            <img
              src=""
              alt=""
            />
          </div>
          <div class="control-button" @click="jumpTo(index - 1)">
            <img
              src=""
              alt=""
            />
          </div>
          <div class="page">
            <input
              type="text"
              v-model="indexPage"
              @focus="inputFocus"
              @blur="inputBlur"
            />
          </div>
          <div class="control-button" @click="jumpTo(index + 1)">
            <img
              src=""
              alt=""
            />
          </div>
          <div class="control-button" @click="jumpTo(pages)">
            <img
              src=""
              alt=""
            />
          </div>
          <div class="control-button" @click="rotateTo">
            <img
              src=""
              alt=""
            />
          </div>
          <div class="control-button" @click="fullScreen">
            <img
              src=""
              alt=""
            />
          </div>
          <div style="width: 85px">
            <el-select
              v-model="scale"
              size="mini"
              placeholder="请选择"
              @change="scaleChange"
            >
              <el-option
                v-for="item in scaleOptions"
                :key="item.value"
                :label="item.label"
                :value="item.value"
              >
              </el-option>
            </el-select>
          </div>
          <el-button
            style="position: absolute; right: 16px"
            size="mini"
            @click="exportImg"
            >导出为图片</el-button
          >
        </div>
        <div>
          <span>文件名称：{{ wjName }}</span>
        </div>
      </div> -->
      <div id="flipbook">
        <canvas
          :class="rotate[rotateIndex]"
          v-for="page in pages"
          :key="page"
          :id="'the-canvas' + page"
        >
        </canvas>
      </div>
    </div>
  </div>
</template>

<script>
import * as PDFJS from 'pdfjs-dist/legacy/build/pdf'
import workerSrc from 'pdfjs-dist/legacy/build/pdf.worker.entry'
PDFJS.workerSrc = workerSrc
import JSZip from 'jszip'
const FileSaver = require('file-saver')
export default {
  props: ['src', 'wjName'],
  data() {
    return {
      pages: 0,
      index: 1,
      scale: 1,
      indexPage: '',
      status: false,
      autoPage: false,
      loading:false,
      autoFc: null,
      io: null,
      hide: true,
      rotateIndex: 0,
      rotate: ['', 'rotate90', 'rotate180', 'rotate270'],
      scaleOptions: [
        {
          label: '50%',
          value: 0.5,
        },
        {
          label: '100%',
          value: 1,
        },
        {
          label: '150%',
          value: 1.5,
        },
        {
          label: '200%',
          value: 2,
        },
      ],
    }
  },
  watch: {
    src: {
      handler: function (val, old) {
        if (val) {
          this._loadFile(val)
        }
      },
      immediate: true,
    },
    index(val, old) {
      if (!isNaN(val)) {
        this.indexPage = `${val}/${this.pages}`
      }
    },
  },
  mounted() {
    this.windowResize()
    document.onkeydown = (e) => {
      const key = e.keyCode
      if (key == 13) {
        this.jumpTo(this.indexPage, true)
      }
    }
  },
  destroyed() {
    this.clearResize()
    document.onkeydown = null
    window.clearInterval(this.autoFc)
  },
  methods: {
    scaleChange(value) {
      const container = document.querySelector('#flipbook')
      const list = container.querySelectorAll('canvas')
      list.forEach((item) => {
        let context = item.getContext('2d')
        const width = item.width
        const height = item.height
        context.clearRect(0, 0, width, height)
      })
      this.scale = value || 1
      this._renderPage(1)
    },
    rotateTo() {
      this.rotateIndex != 3 ? this.rotateIndex++ : (this.rotateIndex = 0)
    },
    showCatalogue() {
      this.hide = !this.hide
      this.$nextTick(() => {
        this._renderCatalogue(1)
        this.jumpToForCatalogue(this.index)
      })
    },
    watchDom() {
      const options = {
        threshold: [0.5],
      }
      const fc = (entries) => {
        let id
        entries.forEach((item) => {
          if (item.intersectionRatio >= 0.5) {
            id = item.target.id
            this.index = parseInt(id.split('the-canvas').pop())
            if (!this.hide) {
              this.jumpToForCatalogue(this.index)
            }
          }
        })
      }
      this.io = new IntersectionObserver(fc, options)
      const main = document.querySelector('#flipbook')
      let list = main.querySelectorAll('canvas')
      list.forEach((item) => {
        this.io.observe(item)
      })
    },
    autoPagerChrome() {
      this.autoPage = !this.autoPage
      this.$message.info(this.autoPage ? '开启自动播放(5秒)' : '关闭自动播放')
      //一直触发
      this.autoFc = window.setInterval(() => {
        if (!this.autoPage) {
          //删除定时器
          window.clearInterval(this.autoFc)
          return
        }
        this.jumpTo(this.index + 1)
      }, 5000)
    },
    clearResize() {
      window.onresize = null
    },
    windowResize() {
      window.onresize = () => {
        this.scaleChange()
      }
    },
    jumpTo(num, boolean) {
      if (this.status && boolean) {
        if (!/^\d+$/.test(num)) {
          this.indexPage = ''
          return
        }
      }
      if (num < 1 || num > this.pages) {
        return
      }
      this.index = parseInt(num)
      const index = num - 1
      const container = document.querySelector('#flipbook')
      const canvas = container.querySelector('canvas')
      const height = canvas.clientHeight + 5
      container.scrollTop = index * height
    },
    jumpToForCatalogue(num) {
      if (num < 1 || num > this.pages || isNaN(num)) {
        return
      }
      const index = num - 1
      const container = document.querySelector('.catalogue')
      const canvas = container.querySelector('canvas')
      const height = canvas.clientHeight + 5
      container.scrollTop = index * height
    },
    inputFocus() {
      this.status = true
      this.indexPage = ''
    },
    inputBlur() {
      this.status = false
      this.indexPage = `${this.index}/${this.pages}`
    },
    _renderCatalogue(num) {
      this.pdfDoc.getPage(num).then((page) => {
        let canvas = document.getElementById('catalogue' + num)
        var vp = page.getViewport({ scale: 0.25 })
        let ctx = canvas.getContext('2d')
        let dpr = window.devicePixelRatio || 1
        let bsr =
          ctx.webkitBackingStorePixelRatio ||
          ctx.mozBackingStorePixelRatio ||
          ctx.msBackingStorePixelRatio ||
          ctx.oBackingStorePixelRatio ||
          ctx.backingStorePixelRatio ||
          1
        let ratio = dpr / bsr
        let container = document.querySelector('.catalogue')
        let viewport = page.getViewport({
          // scale: container.clientWidth / vp.width,
          scale: 0.25,
        })
        canvas.width = 175
        canvas.height = 250 * ratio
        // canvas.style.width = viewport.width + "px";
        canvas.style.width = '175px'
        canvas.style.height = '250px'
        ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
        let renderContext = {
          canvasContext: ctx,
          viewport: viewport,
        }
        page.render(renderContext)
        if (this.pages > num) {
          this._renderCatalogue(num + 1)
        } else {
        }
      })
    },
    _renderPage(num) {
      this.pdfDoc.getPage(num).then((page) => {
        let canvas = document.getElementById('the-canvas' + num)
        var vp = page.getViewport({ scale: this.scale })
        let ctx = canvas.getContext('2d')
        let dpr = window.devicePixelRatio || 1
        let bsr =
          ctx.webkitBackingStorePixelRatio ||
          ctx.mozBackingStorePixelRatio ||
          ctx.msBackingStorePixelRatio ||
          ctx.oBackingStorePixelRatio ||
          ctx.backingStorePixelRatio ||
          1
        let ratio = dpr / bsr
        let container = document.querySelector('.main')
        let viewport = page.getViewport({
          // scale: container.clientWidth / vp.width*this.scale,
          scale: this.scale,
        })
        canvas.width = viewport.width * ratio * this.scale
        canvas.height = viewport.height * ratio * this.scale
        // canvas.style.width = viewport.width + "px";
        canvas.style.width = viewport.width * ratio * this.scale + 'px'
        canvas.style.height = viewport.height * ratio * this.scale + 'px'
        this.$refs.canvasContainer.style.height = viewport.height;
        ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
        let renderContext = {
          canvasContext: ctx,
          viewport: viewport,
        }
        page.render(renderContext)
        if (this.pages > num) {
          this._renderPage(num + 1)
        } else {
          this.watchDom()
        }
      })
    },
    _loadFile(url) {
      // const loading = this.openLoading()
      this.loading = true;
      PDFJS.getDocument(url).promise.then((pdf) => {
        // loading.close()
        this.loading = false;
        this.pdfDoc = pdf
        this.pages = this.pdfDoc.numPages
        this.indexPage = `${this.index}/${this.pages}`
        this.$nextTick(() => {
          this._renderPage(1)
        })
      })
    },
    fullScreen() {
      let res = this.$store.getters.fullScreenGetter
      this.$store.dispatch('setFullScreen', !res)
      res = this.$store.getters.fullScreenGetter
      if (res) {
        this.clearResize()
        this.launchFullScreen()
      } else {
        this.exitFullscreen()
      }
    },
    launchFullScreen() {
      let element = document.documentElement
      if (element.requestFullscreen) {
        element.requestFullscreen()
      } else if (element.mozRequestFullScreen) {
        element.mozRequestFullScreen()
      } else if (element.webkitRequestFullscreen) {
        element.webkitRequestFullscreen()
      } else if (element.msRequestFullscreen) {
        element.msRequestFullscreen()
      }
    },
    exitFullscreen() {
      if (document.exitFullscreen) {
        document.exitFullscreen()
      } else if (document.mozCancelFullScreen) {
        document.mozCancelFullScreen()
      } else if (document.webkitExitFullscreen) {
        document.webkitExitFullscreen()
      }
      setTimeout(() => {
        this.windowResize()
      }, 2000)
    },
    splitBase64(dataurl) {
      var arr = dataurl.split(',')
      return arr[1]
    },
    exportImg() {
      let zip = new JSZip() //创建一个JSZip实例
      let images = zip.folder('images') //创建一个文件夹用来存放图片
      let flipbook = document.querySelector('#flipbook')
      let canvasList = flipbook.querySelectorAll('canvas')
      canvasList.forEach((item, index) => {
        let canvas = document.querySelector('#the-canvas' + (index + 1))
        if (canvas) {
          //将图片放进文件夹images中
          //参数1为图片名称，参数2为图片数据（格式为base64，需去除base64前缀 data:image/png;base64）
          images.file(
            'photo-' + (index + 1) + '.png',
            this.splitBase64(canvas.toDataURL('image/png', 1.0)),
            {
              base64: true,
            },
          )
        }
      })
      //打包下载
      zip
        .generateAsync({
          type: 'blob',
        })
        .then(function (content) {
          FileSaver.saveAs(content, 'picture.zip') //saveAs依赖的js文件是FileSaver.js
        })
    },
  },
}
</script>

<style scoped lang="scss">
.canvas-container {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  min-height: 500px;
  overflow-y: auto;
  // height: 800px;
  background: rgb(247, 248, 249);
  padding: 5px 0;
  // position: relative;
  display: flex;
  .catalogue {
    width: 250px;
    height: 100%;
    transition: all 0.7s ease 0ms;
    overflow-y: auto;
    scroll-behavior: smooth;
    text-align: center;
    canvas {
      cursor: pointer;
      &:hover {
        border: 2px solid rgb(138, 180, 248);
      }
    }
    .checked {
      border: 2px solid rgb(138, 180, 248) !important;
    }
  }
  .catalogue-hide {
    width: 0px;
  }
  // overflow-y: auto;
  // display: flex;
  // flex-wrap: wrap;
  // justify-content: center;
  // canvas {
  //   margin: 0 auto;
  // }
  .main {
    width: 100%;
    height: 100%;
    transition: all 0.7s ease 0ms;
    .header {
      text-align: center;
      .control {
        width: 100%;
        height: 46px;
        position: relative;
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: rgb(44, 127, 153);
        box-shadow: rgb(24, 107, 133) 0px 1px 2px;
        .control-button {
          width: 30px;
          height: 30px;
          display: flex;
          align-items: center;
          justify-content: center;
          cursor: pointer;
          &:hover {
            background: rgba(255, 255, 255, 0.3);
          }
        }
        .page {
          span {
            color: white;
            margin-left: 4px;
          }
          input {
            width: 45px;
            text-align: center;
          }
        }
      }
      .information {
        margin-right: 16px;
      }
    }
    #flipbook {
      height: calc(100% - 67px);
      overflow-y: auto;
      scroll-behavior: smooth;
      text-align: center;
      canvas {
        display: block;
        margin: 0 auto 5px;
      }
      .rotate90 {
        transform: rotate(90deg);
      }
      .rotate180 {
        transform: rotate(180deg);
      }
      .rotate270 {
        transform: rotate(270deg);
      }
    }
  }
  .main-narrow {
    width: calc(100% - 250px);
  }
}
</style>